﻿namespace Legend.Collections
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.Serialization;

    public partial class Collection
    {
        [Serializable]
        private class LazyLoadedList<T>
            : IList<T>
        {
            private IList<T> state;

            /// <summary>
            /// Initializes a new instance of the <see cref="LazyLoadedList&lt;T&gt;"/> class.
            /// </summary>
            /// <param name="collection">The collection.</param>
            public LazyLoadedList(IEnumerable<T> collection)
            {
                this.state = new NonIteratedState(this, collection);
            }

            public int IndexOf(T item)
            {
                return this.state.IndexOf(item);
            }

            public void Insert(int index, T item)
            {
                this.state.Insert(index, item);
            }

            public void RemoveAt(int index)
            {
                this.state.RemoveAt(index);
            }

            public T this[int index]
            {
                get
                {
                    return this.state[index];
                }
                set
                {
                    this.state[index] = value;
                }
            }

            public void Add(T item)
            {
                this.state.Add(item);
            }

            public void Clear()
            {
                this.state.Clear();
            }

            public bool Contains(T item)
            {
                return this.state.Contains(item);
            }

            public void CopyTo(T[] array, int arrayIndex)
            {
                this.state.CopyTo(array, arrayIndex);
            }

            public int Count
            {
                get { return this.state.Count; }
            }

            public bool IsReadOnly
            {
                get { return false; }
            }

            public bool Remove(T item)
            {
                return this.state.Remove(item);
            }

            public IEnumerator<T> GetEnumerator()
            {
                return this.state.GetEnumerator();
            }

            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
            {
                return this.GetEnumerator();
            }

            [OnSerializing]
            private void IterateBeforeSerialization(StreamingContext context)
            {
                this.GetEnumerator();
            }

            private class NonIteratedState
              : IList<T>
            {
                private IEnumerable<T> wrapped;
                private LazyLoadedList<T> parent;

                public NonIteratedState(LazyLoadedList<T> parent, IEnumerable<T> wrapped)
                {
                    this.wrapped = wrapped;
                    this.parent = parent;
                }

                public int IndexOf(T item)
                {
                    return this.Evaluated.IndexOf(item);
                }

                public void Insert(int index, T item)
                {
                    this.Evaluated.Insert(index, item);
                }

                public void RemoveAt(int index)
                {
                    this.Evaluated.RemoveAt(index);
                }

                public T this[int index]
                {
                    get
                    {
                        return this.Evaluated[index];
                    }
                    set
                    {
                        this.Evaluated[index] = value;
                    }
                }

                public void Add(T item)
                {
                    this.Evaluated.Add(item);
                }

                public void Clear()
                {
                    this.parent.state = new List<T>(0);
                }

                public bool Contains(T item)
                {
                    return this.Evaluated.Contains(item);
                }

                public void CopyTo(T[] array, int arrayIndex)
                {
                    this.Evaluated.CopyTo(array, arrayIndex);
                }

                public int Count
                {
                    get { return this.Evaluated.Count; }
                }

                public bool IsReadOnly
                {
                    get { throw new NotSupportedException(); }
                }

                public bool Remove(T item)
                {
                    return this.Evaluated.Remove(item);
                }

                public IEnumerator<T> GetEnumerator()
                {
                    return this.Evaluated.GetEnumerator();
                }

                private IList<T> Evaluated
                {
                    get
                    {
                        this.parent.state = this.wrapped.ToList();
                        return this.parent.state;
                    }
                }

                System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
                {
                    return this.GetEnumerator();
                }
            }
        }
    }
}
